using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using UnityEditor.PackageManager.Requests;
using UnityEngine;
using UnityEngine.Networking;

namespace CalmNine.Framework
{
    /// <summary>
    /// UnityWebRequest��װ��
    /// </summary>
    public class WebClient
    {
        private readonly MonoBehaviour _Executor;

        public WebClient(MonoBehaviour executor)
        {
            _Executor = executor;
        }

        /// <summary>
        /// ��ʼ��UnityWebRequest
        /// </summary>
        /// <param name="request"></param>
        /// <param name="data"></param>
        private void InitUnityWebRequest(UnityWebRequest request, WebRequest data)
        {
            //��ʱ
            request.timeout = data.Timeout;

            //URL
            string queryStr = data.GetQueryString();
            if (!string.IsNullOrEmpty(queryStr))
            {
                request.url += $"?{queryStr}";
            }

            //headers
            var headers = data.GetHeaders();
            foreach (var header in headers)
            {
                request.SetRequestHeader(header.Key, header.Value);
            }

            //�ϴ�������
            if ((request.method == UnityWebRequest.kHttpVerbGET || request.method == UnityWebRequest.kHttpVerbPOST) && data.BodyData != null)
            {
                request.uploadHandler?.Dispose();
                request.uploadHandler = new UploadHandlerRaw(data.BodyData);
            }
        }

        #region GET

        /// <summary>
        /// GET����
        /// </summary>
        /// <param name="req"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public void Get(WebRequest req)
        {
            if (req == null)
            {
                throw new ArgumentNullException(nameof(req));
            }
            _Executor.StartCoroutine(InnerGet(req));
        }
        private IEnumerator InnerGet(WebRequest req)
        {
            req.OnBegin();
            int retryNum = req.RetryCount;
            do
            {
                using (UnityWebRequest request = UnityWebRequest.Get(req.Url))
                {
                    InitUnityWebRequest(request, req);
                    yield return request.SendWebRequest();
                    if (req.IsAbort)
                    {
                        request.Abort();
                        yield break;
                    }
                    bool isSuccess = request.result == UnityWebRequest.Result.Success;
                    if (isSuccess || retryNum == 0)
                    {
                        req.OnComplete(isSuccess, request.responseCode, request.downloadHandler.data, request.error);
                        yield break;
                    }
                    if (req.RetryInterval > 0)
                    {
                        yield return new WaitForSeconds(req.RetryInterval);
                    }
                }
            }
            while (retryNum-- > 0);
        }

        #endregion

        #region POST

        /// <summary>
        /// POST����
        /// </summary>
        /// <param name="req"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public void Post(WebRequest req)
        {
            if (req == null)
            {
                throw new ArgumentNullException(nameof(req));
            }
            _Executor.StartCoroutine(InnerPost(req));
        }
        private IEnumerator InnerPost(WebRequest req)
        {
            req.OnBegin();
            int retryNum = req.RetryCount;
            do
            {
                using (UnityWebRequest request = (req.FormData == null ? UnityWebRequest.PostWwwForm(req.Url, "") : UnityWebRequest.Post(req.Url, req.FormData)))
                {
                    InitUnityWebRequest(request, req);
                    yield return request.SendWebRequest();
                    if (req.IsAbort)
                    {
                        request.Abort();
                        yield break;
                    }
                    bool isSuccess = request.result == UnityWebRequest.Result.Success;
                    if (isSuccess || retryNum == 0)
                    {
                        req.OnComplete(isSuccess, request.responseCode, request.downloadHandler.data, request.error);
                        yield break;
                    }
                }
            }
            while (retryNum-- > 0);
        }

        #endregion
    }
}
